package com.gaocy.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.gaocy.common.api.ApiResult;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;

public class SignUtil {

    private static Logger LOGGER = LoggerFactory.getLogger(SignUtil.class);

    private static final String secretKeyOfWxh = "YgAqeZq1eM#6#xTWkjtEGO%Ol";

    public static void main(String[] args) {
        HashMap<String, String> signMap = new HashMap<String, String>();
        signMap.put("devid", "BC5549D899ED");
        signMap.put("userId", "1");
        signMap.put("aype", "worker");
        signMap.put("name", "中文测试");
        Set<String> keyset = signMap.keySet();
        TreeSet<String> sortSet = new TreeSet<String>();
        sortSet.addAll(keyset);
        Iterator<String> it = sortSet.iterator();
        //step2：把参数的key value链接起来 secretkey放在最后面，得到要加密的字符串
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        //        try {
        //            System.out.println("得到签名sign1:" + getSign(signMap, secretKeyOfWxh));
        //        } catch (UnsupportedEncodingException e) {
        //            e.printStackTrace();
        //        }
    }

    /**
     * 唯修汇外部接口签名验证
     *
     * @param request
     * @return
     */
    public static Boolean checkSign(HttpServletRequest request) throws IOException {
        Boolean flag = false;
        //签名
        String sign = request.getParameter("sign");
        Enumeration<?> pNames = request.getParameterNames();
        InputStream is = null;
        is = request.getInputStream();
        String bodyInfo = IOUtils.toString(is, "utf-8");
        Map<String, String> params = new HashMap<String, String>();
        JSONObject jsonObject = JSONObject.parseObject(bodyInfo);
        //        jsonObject.forEach();
        while (pNames.hasMoreElements()) {
            String pName = (String) pNames.nextElement();
            if ("sign".equals(pName))
                continue;
            String pValue = (String) request.getParameter(pName);
            if(StringUtils.isBlank(pValue)){
                continue;
            }
            params.put(pName, pValue);
        }
        if (sign.equalsIgnoreCase(getSign(params, secretKeyOfWxh))) {
            flag = true;
        }
        return flag;
    }

    public static String utf8Encoding(String value, String sourceCharsetName) {
        try {
            return new String(value.getBytes(sourceCharsetName), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private static byte[] getMD5Digest(String data) throws IOException {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes("UTF-8"));
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse);
        }
        return bytes;
    }

    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
            //sign.append(hex.toLowerCase());
        }
        return sign.toString();
    }

    /**
     * 得到签名
     *
     * @param params 参数集合不含secretkey
     * @param secret 验证接口的secretkey
     * @return
     */
    public static String getSign(Map<String, String> params, String secret) throws UnsupportedEncodingException {
        String sign = "";
        StringBuilder sb = new StringBuilder();
        //step1：先对请求参数排序
        Set<String> keyset = params.keySet();
        TreeSet<String> sortSet = new TreeSet<String>();
        sortSet.addAll(keyset);
        Iterator<String> it = sortSet.iterator();
        //step2：把参数的key value链接起来 secretkey放在最后面，得到要加密的字符串
        while (it.hasNext()) {
            String key = it.next();
            String value = params.get(key);
            sb.append(key).append(value);
        }
        sb.append(secret);
        String data = URLEncoder.encode(sb.toString(), "UTF-8");
        System.out.println(data);
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(data);
            sign = byte2hex(md5Digest);
        } catch (IOException e) {
            LOGGER.error("生成签名错误", e);
        }
        return sign;
    }

    public static ApiResult checkSin(String sign, String timestamp, Object obj) {
        if (StringUtils.isBlank(sign)) {
            return ApiResult.failRequest("签名字段为空");
        }
        if (StringUtils.isBlank(timestamp)) {
            return ApiResult.failRequest("timestamp为空");
        }
        //        Long time = System.currentTimeMillis();
        //        long diff = Long.valueOf(timestamp) - time;
        //        if (Math.abs(diff) > 120000) {
        //            return ResultData.error(new ErrorCode("false",400,"timestamp失效"));
        //        }
        return SignUtil.checkSignByObj(sign, obj);
    }
    public static ApiResult checkSin(String sign, String timestamp, String parameter) {
        if (StringUtils.isBlank(sign)) {
            return ApiResult.failRequest("签名字段为空");
        }
        if (StringUtils.isBlank(timestamp)) {
            return ApiResult.failRequest("timestamp为空");
        }
        //        Long time = System.currentTimeMillis();
        //        long diff = Long.valueOf(timestamp) - time;
        //        if (Math.abs(diff) > 120000) {
        //            return ResultData.error(new ErrorCode("false",400,"timestamp失效"));
        //        }
        return SignUtil.checkSignByObj(sign, parameter + timestamp);
    }

    public static ApiResult checkSignByObj(String signStr,Object object){
        String sign = null;
        List<String> fvs =new ArrayList<>();
        String jsonStr =null;
        if (object != null) {
            jsonStr = JSON.toJSONString(object, SerializerFeature.SortField.MapSortField);
            jsonStr+=secretKeyOfWxh;
            System.out.println(jsonStr);
            byte[] md5Digest;
            try {
                //得到Md5加密得到sign
                md5Digest = getMD5Digest(jsonStr);
                sign = byte2hex(md5Digest);
            } catch (IOException e) {
                LOGGER.error("生成签名错误", e);
            }
        }
        if(signStr.equalsIgnoreCase(sign)){
            return null;
        }else{
            return ApiResult.failRequest("sign签名校验失败,str:"+jsonStr+",sign:"+sign);
        }
    }

    public static ApiResult checkSignByStr(String signStr,String parameter){
        String sign = null;
        if (StringUtils.isNotBlank(parameter)) {
            System.out.println(parameter);
            byte[] md5Digest;
            try {
                //得到Md5加密得到sign
                md5Digest = getMD5Digest(parameter);
                sign = byte2hex(md5Digest);
            } catch (IOException e) {
                LOGGER.error("生成签名错误", e);
            }
        }
        if(signStr.equalsIgnoreCase(sign)){
            return null;
        }else{
            return ApiResult.failRequest("sign签名校验失败,str:"+parameter+",sign:"+sign);
        }
    }




    // 把一个字符串的第一个字母大写、效率是最高的、
    private static String getMethodName(String fildeName){
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }


}
